1   /*
2    * Copyright (C) 2008 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.primitives;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  import static java.lang.Double.NaN;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.base.Converter;
24  import com.google.common.collect.testing.Helpers;
25  
26  import junit.framework.TestCase;
27  
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.Comparator;
32  import java.util.List;
33  
34  /**
35   * Unit test for {@link Doubles}.
36   *
37   * @author Kevin Bourrillion
38   */
39  @GwtCompatible(emulated = true)
40  @SuppressWarnings("cast") // redundant casts are intentional and harmless
41  public class DoublesTest extends TestCase {
42    private static final double[] EMPTY = {};
43    private static final double[] ARRAY1 = {(double) 1};
44    private static final double[] ARRAY234
45        = {(double) 2, (double) 3, (double) 4};
46  
47    private static final double LEAST = Double.NEGATIVE_INFINITY;
48    private static final double GREATEST = Double.POSITIVE_INFINITY;
49  
50    private static final double[] NUMBERS = new double[] {
51        LEAST, -Double.MAX_VALUE, -1.0, -0.5, -0.1, -0.0, 0.0, 0.1, 0.5, 1.0,
52        Double.MAX_VALUE, GREATEST, Double.MIN_NORMAL, -Double.MIN_NORMAL,
53        Double.MIN_VALUE, -Double.MIN_VALUE, Integer.MIN_VALUE,
54        Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE
55    };
56  
57    private static final double[] VALUES
58        = Doubles.concat(NUMBERS, new double[] {NaN});
59  
60    public void testHashCode() {
61      for (double value : VALUES) {
62        assertEquals(((Double) value).hashCode(), Doubles.hashCode(value));
63      }
64    }
65  
66    public void testIsFinite() {
67      for (double value : NUMBERS) {
68        assertEquals(!(Double.isNaN(value) || Double.isInfinite(value)), Doubles.isFinite(value));
69      }
70    }
71  
72    public void testCompare() {
73      for (double x : VALUES) {
74        for (double y : VALUES) {
75          // note: spec requires only that the sign is the same
76          assertEquals(x + ", " + y,
77                       Double.valueOf(x).compareTo(y),
78                       Doubles.compare(x, y));
79        }
80      }
81    }
82  
83    public void testContains() {
84      assertFalse(Doubles.contains(EMPTY, (double) 1));
85      assertFalse(Doubles.contains(ARRAY1, (double) 2));
86      assertFalse(Doubles.contains(ARRAY234, (double) 1));
87      assertTrue(Doubles.contains(new double[] {(double) -1}, (double) -1));
88      assertTrue(Doubles.contains(ARRAY234, (double) 2));
89      assertTrue(Doubles.contains(ARRAY234, (double) 3));
90      assertTrue(Doubles.contains(ARRAY234, (double) 4));
91  
92      for (double value : NUMBERS) {
93        assertTrue("" + value,
94            Doubles.contains(new double[] {5.0, value}, value));
95      }
96      assertFalse(Doubles.contains(new double[] {5.0, NaN}, NaN));
97    }
98  
99    public void testIndexOf() {
100     assertEquals(-1, Doubles.indexOf(EMPTY, (double) 1));
101     assertEquals(-1, Doubles.indexOf(ARRAY1, (double) 2));
102     assertEquals(-1, Doubles.indexOf(ARRAY234, (double) 1));
103     assertEquals(0, Doubles.indexOf(
104         new double[] {(double) -1}, (double) -1));
105     assertEquals(0, Doubles.indexOf(ARRAY234, (double) 2));
106     assertEquals(1, Doubles.indexOf(ARRAY234, (double) 3));
107     assertEquals(2, Doubles.indexOf(ARRAY234, (double) 4));
108     assertEquals(1, Doubles.indexOf(
109         new double[] { (double) 2, (double) 3, (double) 2, (double) 3 },
110         (double) 3));
111 
112     for (double value : NUMBERS) {
113       assertEquals("" + value,
114           1, Doubles.indexOf(new double[] {5.0, value}, value));
115     }
116     assertEquals(-1, Doubles.indexOf(new double[] {5.0, NaN}, NaN));
117   }
118 
119   public void testIndexOf_arrayTarget() {
120     assertEquals(0, Doubles.indexOf(EMPTY, EMPTY));
121     assertEquals(0, Doubles.indexOf(ARRAY234, EMPTY));
122     assertEquals(-1, Doubles.indexOf(EMPTY, ARRAY234));
123     assertEquals(-1, Doubles.indexOf(ARRAY234, ARRAY1));
124     assertEquals(-1, Doubles.indexOf(ARRAY1, ARRAY234));
125     assertEquals(0, Doubles.indexOf(ARRAY1, ARRAY1));
126     assertEquals(0, Doubles.indexOf(ARRAY234, ARRAY234));
127     assertEquals(0, Doubles.indexOf(
128         ARRAY234, new double[] { (double) 2, (double) 3 }));
129     assertEquals(1, Doubles.indexOf(
130         ARRAY234, new double[] { (double) 3, (double) 4 }));
131     assertEquals(1, Doubles.indexOf(ARRAY234, new double[] { (double) 3 }));
132     assertEquals(2, Doubles.indexOf(ARRAY234, new double[] { (double) 4 }));
133     assertEquals(1, Doubles.indexOf(new double[] { (double) 2, (double) 3,
134         (double) 3, (double) 3, (double) 3 },
135         new double[] { (double) 3 }
136     ));
137     assertEquals(2, Doubles.indexOf(
138         new double[] { (double) 2, (double) 3, (double) 2,
139             (double) 3, (double) 4, (double) 2, (double) 3},
140         new double[] { (double) 2, (double) 3, (double) 4}
141     ));
142     assertEquals(1, Doubles.indexOf(
143         new double[] { (double) 2, (double) 2, (double) 3,
144             (double) 4, (double) 2, (double) 3, (double) 4},
145         new double[] { (double) 2, (double) 3, (double) 4}
146     ));
147     assertEquals(-1, Doubles.indexOf(
148         new double[] { (double) 4, (double) 3, (double) 2},
149         new double[] { (double) 2, (double) 3, (double) 4}
150     ));
151 
152     for (double value : NUMBERS) {
153       assertEquals("" + value, 1, Doubles.indexOf(
154           new double[] {5.0, value, value, 5.0}, new double[] {value, value}));
155     }
156     assertEquals(-1, Doubles.indexOf(
157         new double[] {5.0, NaN, NaN, 5.0}, new double[] {NaN, NaN}));
158   }
159 
160   public void testLastIndexOf() {
161     assertEquals(-1, Doubles.lastIndexOf(EMPTY, (double) 1));
162     assertEquals(-1, Doubles.lastIndexOf(ARRAY1, (double) 2));
163     assertEquals(-1, Doubles.lastIndexOf(ARRAY234, (double) 1));
164     assertEquals(0, Doubles.lastIndexOf(
165         new double[] {(double) -1}, (double) -1));
166     assertEquals(0, Doubles.lastIndexOf(ARRAY234, (double) 2));
167     assertEquals(1, Doubles.lastIndexOf(ARRAY234, (double) 3));
168     assertEquals(2, Doubles.lastIndexOf(ARRAY234, (double) 4));
169     assertEquals(3, Doubles.lastIndexOf(
170         new double[] { (double) 2, (double) 3, (double) 2, (double) 3 },
171         (double) 3));
172 
173     for (double value : NUMBERS) {
174       assertEquals("" + value,
175           0, Doubles.lastIndexOf(new double[] {value, 5.0}, value));
176     }
177     assertEquals(-1, Doubles.lastIndexOf(new double[] {NaN, 5.0}, NaN));
178   }
179 
180   public void testMax_noArgs() {
181     try {
182       Doubles.max();
183       fail();
184     } catch (IllegalArgumentException expected) {
185     }
186   }
187 
188   public void testMax() {
189     assertEquals(LEAST, Doubles.max(LEAST));
190     assertEquals(GREATEST, Doubles.max(GREATEST));
191     assertEquals((double) 9, Doubles.max(
192         (double) 8, (double) 6, (double) 7,
193         (double) 5, (double) 3, (double) 0, (double) 9));
194 
195     assertEquals(0.0, Doubles.max(-0.0, 0.0));
196     assertEquals(0.0, Doubles.max(0.0, -0.0));
197     assertEquals(GREATEST, Doubles.max(NUMBERS));
198     assertTrue(Double.isNaN(Doubles.max(VALUES)));
199   }
200 
201   public void testMin_noArgs() {
202     try {
203       Doubles.min();
204       fail();
205     } catch (IllegalArgumentException expected) {
206     }
207   }
208 
209   public void testMin() {
210     assertEquals(LEAST, Doubles.min(LEAST));
211     assertEquals(GREATEST, Doubles.min(GREATEST));
212     assertEquals((double) 0, Doubles.min(
213         (double) 8, (double) 6, (double) 7,
214         (double) 5, (double) 3, (double) 0, (double) 9));
215 
216     assertEquals(-0.0, Doubles.min(-0.0, 0.0));
217     assertEquals(-0.0, Doubles.min(0.0, -0.0));
218     assertEquals(LEAST, Doubles.min(NUMBERS));
219     assertTrue(Double.isNaN(Doubles.min(VALUES)));
220   }
221 
222   public void testConcat() {
223     assertTrue(Arrays.equals(EMPTY, Doubles.concat()));
224     assertTrue(Arrays.equals(EMPTY, Doubles.concat(EMPTY)));
225     assertTrue(Arrays.equals(EMPTY, Doubles.concat(EMPTY, EMPTY, EMPTY)));
226     assertTrue(Arrays.equals(ARRAY1, Doubles.concat(ARRAY1)));
227     assertNotSame(ARRAY1, Doubles.concat(ARRAY1));
228     assertTrue(Arrays.equals(ARRAY1, Doubles.concat(EMPTY, ARRAY1, EMPTY)));
229     assertTrue(Arrays.equals(
230         new double[] {(double) 1, (double) 1, (double) 1},
231         Doubles.concat(ARRAY1, ARRAY1, ARRAY1)));
232     assertTrue(Arrays.equals(
233         new double[] {(double) 1, (double) 2, (double) 3, (double) 4},
234         Doubles.concat(ARRAY1, ARRAY234)));
235   }
236 
237   public void testEnsureCapacity() {
238     assertSame(EMPTY, Doubles.ensureCapacity(EMPTY, 0, 1));
239     assertSame(ARRAY1, Doubles.ensureCapacity(ARRAY1, 0, 1));
240     assertSame(ARRAY1, Doubles.ensureCapacity(ARRAY1, 1, 1));
241     assertTrue(Arrays.equals(
242         new double[] {(double) 1, (double) 0, (double) 0},
243         Doubles.ensureCapacity(ARRAY1, 2, 1)));
244   }
245 
246   public void testEnsureCapacity_fail() {
247     try {
248       Doubles.ensureCapacity(ARRAY1, -1, 1);
249       fail();
250     } catch (IllegalArgumentException expected) {
251     }
252     try {
253       // notice that this should even fail when no growth was needed
254       Doubles.ensureCapacity(ARRAY1, 1, -1);
255       fail();
256     } catch (IllegalArgumentException expected) {
257     }
258   }
259 
260   public void testJoinNonTrivialDoubles() {
261     assertEquals("", Doubles.join(",", EMPTY));
262     assertEquals("1.2", Doubles.join(",", 1.2));
263     assertEquals("1.3,2.4", Doubles.join(",", 1.3, 2.4));
264     assertEquals("1.42.53.6", Doubles.join("", 1.4, 2.5, 3.6));
265   }
266 
267   public void testLexicographicalComparator() {
268     List<double[]> ordered = Arrays.asList(
269         new double[] {},
270         new double[] {LEAST},
271         new double[] {LEAST, LEAST},
272         new double[] {LEAST, (double) 1},
273         new double[] {(double) 1},
274         new double[] {(double) 1, LEAST},
275         new double[] {GREATEST, Double.MAX_VALUE},
276         new double[] {GREATEST, GREATEST},
277         new double[] {GREATEST, GREATEST, GREATEST});
278 
279     Comparator<double[]> comparator = Doubles.lexicographicalComparator();
280     Helpers.testComparator(comparator, ordered);
281   }
282 
283   public void testToArray() {
284     // need explicit type parameter to avoid javac warning!?
285     List<Double> none = Arrays.<Double>asList();
286     assertTrue(Arrays.equals(EMPTY, Doubles.toArray(none)));
287 
288     List<Double> one = Arrays.asList((double) 1);
289     assertTrue(Arrays.equals(ARRAY1, Doubles.toArray(one)));
290 
291     double[] array = {(double) 0, (double) 1, Math.PI};
292 
293     List<Double> three = Arrays.asList((double) 0, (double) 1, Math.PI);
294     assertTrue(Arrays.equals(array, Doubles.toArray(three)));
295 
296     assertTrue(Arrays.equals(array, Doubles.toArray(Doubles.asList(array))));
297   }
298 
299   public void testToArray_threadSafe() {
300     for (int delta : new int[] { +1, 0, -1 }) {
301       for (int i = 0; i < VALUES.length; i++) {
302         List<Double> list = Doubles.asList(VALUES).subList(0, i);
303         Collection<Double> misleadingSize =
304             Helpers.misleadingSizeCollection(delta);
305         misleadingSize.addAll(list);
306         double[] arr = Doubles.toArray(misleadingSize);
307         assertEquals(i, arr.length);
308         for (int j = 0; j < i; j++) {
309           assertEquals(VALUES[j], arr[j]);
310         }
311       }
312     }
313   }
314 
315   public void testToArray_withNull() {
316     List<Double> list = Arrays.asList((double) 0, (double) 1, null);
317     try {
318       Doubles.toArray(list);
319       fail();
320     } catch (NullPointerException expected) {
321     }
322   }
323 
324   public void testToArray_withConversion() {
325     double[] array = {(double) 0, (double) 1, (double) 2};
326 
327     List<Byte> bytes = Arrays.asList((byte) 0, (byte) 1, (byte) 2);
328     List<Short> shorts = Arrays.asList((short) 0, (short) 1, (short) 2);
329     List<Integer> ints = Arrays.asList(0, 1, 2);
330     List<Float> floats = Arrays.asList((float) 0, (float) 1, (float) 2);
331     List<Long> longs = Arrays.asList((long) 0, (long) 1, (long) 2);
332     List<Double> doubles = Arrays.asList((double) 0, (double) 1, (double) 2);
333 
334     assertTrue(Arrays.equals(array, Doubles.toArray(bytes)));
335     assertTrue(Arrays.equals(array, Doubles.toArray(shorts)));
336     assertTrue(Arrays.equals(array, Doubles.toArray(ints)));
337     assertTrue(Arrays.equals(array, Doubles.toArray(floats)));
338     assertTrue(Arrays.equals(array, Doubles.toArray(longs)));
339     assertTrue(Arrays.equals(array, Doubles.toArray(doubles)));
340   }
341 
342   public void testAsList_isAView() {
343     double[] array = {(double) 0, (double) 1};
344     List<Double> list = Doubles.asList(array);
345     list.set(0, (double) 2);
346     assertTrue(Arrays.equals(new double[] {(double) 2, (double) 1}, array));
347     array[1] = (double) 3;
348     assertThat(list).has().exactly((double) 2, (double) 3).inOrder();
349   }
350 
351   public void testAsList_toArray_roundTrip() {
352     double[] array = { (double) 0, (double) 1, (double) 2 };
353     List<Double> list = Doubles.asList(array);
354     double[] newArray = Doubles.toArray(list);
355 
356     // Make sure it returned a copy
357     list.set(0, (double) 4);
358     assertTrue(Arrays.equals(
359         new double[] { (double) 0, (double) 1, (double) 2 }, newArray));
360     newArray[1] = (double) 5;
361     assertEquals((double) 1, (double) list.get(1));
362   }
363 
364   // This test stems from a real bug found by andrewk
365   public void testAsList_subList_toArray_roundTrip() {
366     double[] array = { (double) 0, (double) 1, (double) 2, (double) 3 };
367     List<Double> list = Doubles.asList(array);
368     assertTrue(Arrays.equals(new double[] { (double) 1, (double) 2 },
369         Doubles.toArray(list.subList(1, 3))));
370     assertTrue(Arrays.equals(new double[] {},
371         Doubles.toArray(list.subList(2, 2))));
372   }
373 
374   public void testAsListEmpty() {
375     assertSame(Collections.emptyList(), Doubles.asList(EMPTY));
376   }
377 
378   /**
379    * A reference implementation for {@code tryParse} that just catches the exception from
380    * {@link Double#valueOf}.
381    */
382   private static Double referenceTryParse(String input) {
383     if (input.trim().length() < input.length()) {
384       return null;
385     }
386     try {
387       return Double.valueOf(input);
388     } catch (NumberFormatException e) {
389       return null;
390     }
391   }
392 
393   private static final String[] BAD_TRY_PARSE_INPUTS =
394     { "", "+-", "+-0", " 5", "32 ", " 55 ", "infinity", "POSITIVE_INFINITY", "0x9A", "0x9A.bE-5",
395       ".", ".e5", "NaNd", "InfinityF" };
396 
397   public void testStringConverter_convert() {
398     Converter<String, Double> converter = Doubles.stringConverter();
399     assertEquals((Double) 1.0, converter.convert("1.0"));
400     assertEquals((Double) 0.0, converter.convert("0.0"));
401     assertEquals((Double) (-1.0), converter.convert("-1.0"));
402     assertEquals((Double) 1.0, converter.convert("1"));
403     assertEquals((Double) 0.0, converter.convert("0"));
404     assertEquals((Double) (-1.0), converter.convert("-1"));
405     assertEquals((Double) 1e6, converter.convert("1e6"));
406     assertEquals((Double) 1e-6, converter.convert("1e-6"));
407   }
408 
409   public void testStringConverter_convertError() {
410     try {
411       Doubles.stringConverter().convert("notanumber");
412       fail();
413     } catch (NumberFormatException expected) {
414     }
415   }
416 
417   public void testStringConverter_nullConversions() {
418     assertNull(Doubles.stringConverter().convert(null));
419     assertNull(Doubles.stringConverter().reverse().convert(null));
420   }
421 }
422